import {Application, Container, Graphics, RenderTexture, Sprite, Texture} from "pixi.js";

// 引入接口
type AlignContentToContainerGeometry = Omit<GeometryInterface, "scale">;

// 内容几何信息数据接口
interface AlignContentToContainerGeometryInterface
{
    content: AlignContentToContainerGeometry; // 内容几何信息
    container: AlignContentToContainerGeometry; // 容器几何信息
    limit?: number; // 限制大小比例
    scale?: number | string; // 缩放比例
}

/**
 * 工具类
 * */
class CanvasTools
{
    // 实例
    private static app: Application;

    /**
     * 构造函数
     * @param {Object} argumentsList 参数列表 {app(对象): Application;}
     * */
    constructor(argumentsList: Record<string, any>)
    {
        CanvasTools.app = argumentsList.app;
    }

    /**
     * 找到指定的绘制数据
     * @param {Sprite | Container<any> | any[]} data 绘制数据
     * @param {string} name 绘制数据的别名
     * @return {Sprite | Container<any> | null} 返回找到的绘制数据
     * */
    getApplicationSourceData<T extends Sprite | Container<any>>(data: Sprite | Container<any> | any[], name: string): T | null
    {
        // 判断当前别名是否和指定的一致，如果一致则返回当前数据
        if ((data instanceof Sprite || data instanceof Container) && isObject(data) && data.label && data.label === name)
        {
            return data as T;
        }

        // 如果 data 是数组，遍历数组中的每个元素
        if (isArray(data))
        {
            for (const item of data)
            {
                const currentData = item as Sprite | Container<any>;

                const result = this.getApplicationSourceData(currentData, name);

                if (result)
                {
                    return result as T;
                }
            }
        }

        // 如果 data 有 children 属性，并且 children 不为空，递归调用 getCanvasTarget 方法
        if (data instanceof Container && data.children && !isEmpty(data.children))
        {
            return this.getApplicationSourceData(data.children, name);
        }

        // 如果没有找到匹配的元素，返回 null
        return null;
    }

    /**
     * 刷新图片蒙版尺寸
     * @param {Sprite} image 图片对象
     * @param {DrawingBoardGeometryInterface} geometry 画板几何信息
     * */
    refreshImageMaskGeometry(image: Sprite, geometry: DrawingBoardGeometryInterface): void
    {
        if (!image)
        {
            return;
        }

        image.setMask({
            mask: new Graphics().rect(geometry.x, geometry.y, geometry.width, geometry.height).fill(),
            inverse: false
        });
    }

    /**
     * 内容相对容器居中
     * @param {AlignContentToContainerGeometry} argumentsList 参数列表(content: 内容几何信息, container: 容器几何信息, limit: 限制缩放比例, scale: 缩放比例)
     * @return {Object} 返回居中后的几何信息(width: 宽度, height: 高度, x: x轴偏移量, y: y轴偏移量, scale: 缩放比例)
     * */
    alignContentToContainer(argumentsList: AlignContentToContainerGeometryInterface): {width: number; height: number; scale: number; x: number; y: number}
    {
        const {content: {width: contentWidth = 0, height: contentHeight = 0}, container: {width: containerWidth = 0, height: containerHeight = 0}} = argumentsList || {};

        // 限制缩放比例
        const limit = argumentsList.limit || 1;

        // 计算比例因子
        const widthRatio = containerWidth * limit / contentWidth;
        const heightRatio = containerHeight * limit / contentHeight;

        // 计算缩放后尺寸
        const computedScale = (argumentsList.scale === "auto" ? Math.min(widthRatio, heightRatio) : isString(argumentsList.scale) ? Number(argumentsList.scale) : argumentsList.scale) || Math.min(widthRatio, heightRatio);

        // 计算缩放后尺寸
        const scaleWidth = contentWidth * computedScale;
        const scaleHeight = contentHeight * computedScale;

        return {
            width: scaleWidth,
            height: scaleHeight,
            x: (containerWidth - scaleWidth) / 2,
            y: (containerHeight - scaleHeight) / 2,
            scale: computedScale
        };
    }

    /**
     * 获取当前鼠标局部坐标系
     * @param {Object} argumentsList 参数列表(event: 事件对象, container: 容器)
     * @return {Object} 鼠标局部坐标系(x: x轴偏移量, y: y轴偏移量)
     * */
    getMouseLocalPos(argumentsList: {event: Record<string, any>; container: Container<any>}): {x: number; y: number}
    {
        const {event, container} = argumentsList || {};

        // 获取鼠标相对容器的位置
        const {x, y} = event.data.getLocalPosition(container);

        return {
            x,
            y
        };
    }

    /**
     * 创建网格
     * @param {Object} argumentsList 参数列表(width: 宽度, height: 高度, gap: 间隙)
     * @return {Object} 返回创建的网格纹理
     * */
    createGridTexture(argumentsList: {width: number; height: number; gap: number}): RenderTexture
    {
        const {width = 0, height = 0, gap = 0} = argumentsList || {};

        // 透明色
        const lightColor = 0xebebeb;

        // 深灰色
        const darkColor = 0xcccccc;

        // 创建离屏画布
        const offscreenCanvas = new Container();

        // 创建纹理
        const renderTexture = RenderTexture.create({width: width, height: height});

        // 在离屏画布绘制内容
        const graphics = new Graphics();

        // 绘制网格列
        for (let y = 0; y < height; y += gap)
        {
            // 绘制网格行
            for (let x = 0; x < width; x += gap)
            {
                // 计算当前行的索引
                const rowIndex = Math.floor(y / gap);

                // 计算当前列的索引
                const columnIndex = Math.floor(x / gap);

                // 根据行和列的索引判断颜色
                const isLightColor = (rowIndex % 2 === 0 && columnIndex % 2 === 0) || (rowIndex % 2 !== 0 && columnIndex % 2 !== 0);

                // 绘制网格矩形
                graphics.rect(x, y, gap, gap);

                // 设置填充颜色
                graphics.fill({color: isLightColor ? lightColor : darkColor});
            }
        }

        offscreenCanvas.addChild(graphics);

        // 将离屏内容渲染到纹理
        CanvasTools.app.renderer.render({container: offscreenCanvas, target: renderTexture, clear: true});

        // 及时销毁临时对象
        offscreenCanvas.destroy({children: true});

        return renderTexture;
    }

    /**
     * 调试器
     * @param {Texture | HTMLCanvasElement | HTMLCanvasElement[]} container 容器
     * */
    debug(container: Texture | HTMLCanvasElement | HTMLCanvasElement[]): void
    {
        // 创建临时画布
        const currentApp = new Application();

        currentApp.init({
            // 背景alpha
            backgroundAlpha: 0,
            // 抗锯齿
            antialias: false,
            // 自动渲染
            autoStart: true,
            // 自动缩放
            autoDensity: false,
            // 分辨率
            resolution: CanvasTools.app.renderer.resolution,
            // 每次渲染前清除画布
            clearBeforeRender: true
        }).then(() =>
        {
            if (container instanceof Texture)
            {
                // 创建临时精灵
                const tempSprite = new Sprite(container);

                // 加入渲染树并强制渲染
                currentApp.stage.addChild(tempSprite);

                // 关键！触发实际渲染
                currentApp.renderer.render(currentApp.stage);

                // 获取画布
                const canvas = currentApp.renderer.extract.canvas(tempSprite) as HTMLCanvasElement;

                appendCanvas(canvas);
            }
            else
            {
                if (isArray(container))
                {
                    container.forEach((item: HTMLCanvasElement) =>
                    {
                        appendCanvas(item);
                    });
                }
                else
                {
                    appendCanvas(container as HTMLCanvasElement);
                }
            }
        });

        function appendCanvas(canvas: HTMLCanvasElement)
        {
            // 找到当前已经存在的调试canvas
            const debugCanvas = document.querySelectorAll<HTMLElement>(".debug-canvas");

            // 将调试canvas添加到界面
            const debugContainer = document.createElement("div");
            debugContainer.className = "debug-canvas";
            debugContainer.style.position = "fixed";
            debugContainer.style.width = "104px";
            debugContainer.style.height = "104px";
            debugContainer.style.right = "10px";
            debugContainer.style.zIndex = "999999";
            debugContainer.style.border = "2px solid red";
            debugContainer.style.display = "flex";
            debugContainer.style.alignItems = "center";
            debugContainer.style.justifyContent = "center";
            debugContainer.style.backgroundColor = "red";

            const canvasContainerInfo = document.createElement("div");
            canvasContainerInfo.innerText = `${canvas.width}, ${canvas.height}`;
            canvasContainerInfo.style.position = "absolute";
            canvasContainerInfo.style.color = "red";
            canvasContainerInfo.style.fontSize = "12px";
            canvasContainerInfo.style.top = "2px";
            canvasContainerInfo.style.left = "2px";
            canvasContainerInfo.style.lineHeight = "12px";
            canvasContainerInfo.style.padding = "4px 6px";
            canvasContainerInfo.style.borderRadius = "20px";
            canvasContainerInfo.style.backgroundColor = "rgba(255, 255, 255, 0.9)";

            debugContainer.appendChild(canvasContainerInfo);

            // 设置调试canvas的位置
            if (debugCanvas.length > 0)
            {
                const lastCanvas = debugCanvas[debugCanvas.length - 1];
                const lastBottom = lastCanvas.offsetTop + lastCanvas.offsetHeight;
                debugContainer.style.top = `${lastBottom + 10}px`; // 间隔10px
            }
            else
            {
                debugContainer.style.top = "10px";
            }

            // 设置画布的宽
            canvas.style.maxWidth = "100%";

            // 设置画布的高
            canvas.style.maxHeight = "100%";

            // 创建调试canvas
            debugContainer.appendChild(canvas);

            // 将调试canvas添加到界面
            document.body.appendChild(debugContainer);
        }
    }
}

export default CanvasTools;